const fs = require('fs')
const path = require('path')
const config = require(process.cwd() + '/src/config/config')
const commonUtils = require(process.cwd() + '/src/utils/common')
const env = require(process.cwd() + '/src/utils/env')
const tiles = require(process.cwd() + '/src/utils/tiles')
const fileUtils = require(process.cwd() + '/src/utils/file')

class MapsSetting {
  constructor () {
    this.settingFileName = 'mapsSetting.json'
    this.maps = []
  }
  
  // 初始化，读文件
  async init () {
    const settingPath = config.mapsPath + this.settingFileName
    // 打开配置文件
    let mapData = await fs.promises.readFile(settingPath)
    this.maps = JSON.parse(mapData)
  }
  
  // 保存配置
  async save () {
    const settingPath = config.mapsPath + this.settingFileName
    const buffer = JSON.stringify(this.maps)
    await fs.promises.writeFile(settingPath, buffer)
  }
  
  // 导出所有地图,
  async output () {
    // 创建maps文件夹,存放地图数据
    const mapsPath = config.outputPath + 'maps'
    await fileUtils.createFolder(mapsPath)
    
    let outputProgresses = []
    const len = this.maps.length
    for (let i = 0; i < len; i++) {
      let progress = this.outputMap(this.maps[i])
      outputProgresses.push(progress)
    }
    
    await Promise.all(outputProgresses)
  }
  
  // 导出单张地图
  async outputMap (map) {
    if (map.file) {
      // 有file文件,导出地图文件
      await this.outputMapData(map.file)
    }
    
    if (map.children) {
      let outputProgresses = []
      const len = map.children.length
      for (let i = 0; i < len; i++) {
        let progress = this.outputMap(map.children[i])
        outputProgresses.push(progress)
      }
      
      await Promise.all(outputProgresses)
    }
  }
  
  // 导出地图文件
  async outputMapData (mapFile) {
    // 获取配置信息
    const mapsPath = config.mapsPath + mapFile
    let data = await fs.promises.readFile(mapsPath)
    data = JSON.parse(data)
    
    // 解析配置信息中所有的资源路径
    data = await tiles.analyseSrc(data)
    
    // 写入新文件
    const writeMapsPath = path.join(config.outputPath + 'maps', mapFile)
    const buffer = JSON.stringify(data)
    await fs.promises.writeFile(writeMapsPath, buffer)
  }
  
  // 获取导出的地图列表
  async getOutputList () {
    let mapsList = await fs.promises.readdir(config.outputPath + 'maps')
    return mapsList.map((map) => {
      const index = map.indexOf('_')
      let mapName = map.slice(index + 1)
      return fileUtils.cutFileTail(mapName)
    })
  }
  
  // 打开指定的地图文件
  async openMap (id) {
    let map = this.getMapById(id)
    if (!map || !map.file) {
      // 地图不存在或者文件不存在
      return null
    }
    
    const filePath = config.mapsPath + map.file
    let data = await fs.promises.readFile(filePath)
    data = JSON.parse(data)
    data = await tiles.analyseSrc(data)
    return data
  }
  
  // 保存地图数据
  async setMap (id, data) {
    let map = this.getMapById(id)
    if (!map || !map.file) {
      // 地图不存在或者文件不存在
      return null
    }
    data = tiles.zipSrc(data)
    
    const filePath = config.mapsPath + map.file
    const buffer = JSON.stringify(data)
    await fs.promises.writeFile(filePath, buffer)
  }
  
  // 创建一个地图文件
  async addMapFile (id, settings) {
    let map = this.getMapById(id)
    if (!map) {
      // 地图不存在或者文件不存在
      return Promise.reject('地图不存在')
    }
    
    // 记录地图文件
    const fileName = 'map_' + map.id + '.json'
    const filePath = config.mapsPath + fileName
    map.file = fileName
    
    // 生成地图文件数据
    let mapFileData = this.initMapFile(id, map.name, settings)
    
    // 保存文件
    const buffer = JSON.stringify(mapFileData)
    await fs.promises.writeFile(filePath, buffer)
    return mapFileData
  }
  
  // 获取地图的资源库
  async getPreparations (preparations) {  
    if (!preparations || typeof preparations != 'object') {
      // preparation字段不存在
      return {}
    }
    
    let result = {
      // 环境、角色、互动
      env: [],
      roles: [],
      trigger: []
    }
    // 获取env
    if (preparations.env) {
      const len = preparations.env.length
      for (let i = 0; i < len; i++) {
        const name = preparations.env[i]
        try {
          let data = await env.getEnv(name)
          data.name = name
          result.env.push(data)
        }
        catch (e) {
          console.log(name + '环境文件打开失败')
          console.log(e)
        }
      }
    }
    
    // 获取角色roles
    
    // 获取互动triggers
    
    // 返回结果
    return result
  }
  
  // 初始化一个地图对象
  initMap (name) {
    // id为当前时间戳 + 8位随机串
    const id = new Date().getTime() + commonUtils.randomString(false, 8)
    return {
      id: id,
      name: name,
      children: []
    }
  }
  
  // 初始化一个地图文件
  initMapFile (id, name, settings) {
    let data =  {
      id: id,
      name: name,
      rowNum: settings.row,
      colNum: settings.col,
      // 预备资源列表
      preparations: {
        // 环境资源
        env: [],
        // 角色资源
        roles: [],
        // 动态互动资源
        dynamic: []
      },
      // 地图图块
      items: [],
    }
    
    const len = settings.row * settings.col
    for (let i = 0; i < len; i++) {
      const rowIndex = Math.floor(i / settings.col)
      const colIndex = i % settings.col
      data.items.push({
        rowIndex: rowIndex,
        colIndex: colIndex,
        /*
          对象列表共有5层
          1.地表环境
          2.装饰环境1
          3.装饰环境2
          4.互动
          5.角色
          创建地图是会先放完所有的1,再放所有的2,以此类推,在layer相同的情况下,5是最上面的一层
          层并不决定覆盖次序,真正决定覆盖次序的是layer
          角色因为是动态创建,所以角色单独存放于一个角色层,不会和其他静态事物一样添加进大舞台,角色层的layer为30,layer大于30的其他事物将覆盖所有角色
        */
        objects: []
      })
    }
    
    return data
  }
  
  // 在parentId节点中插入名为name的新地图
  addChild (parentId, name) {
    // 创建新地图
    const newMap = this.initMap(name)
    if (!parentId) {
      // 未指定parentId，添加到根节点
      this.maps.push(newMap)
    }
    else {
      // 找到父节点，插入子节点
      let parentMap = this.getMapById(parentId)
      console.log(parentMap)
      if (parentMap) {
        parentMap.children.push(newMap)  
      }
    }
  }
 
  // 重命名某一个节点
  async renameMap (id, name) {
    let map = this.getMapById(id)
    if (map) {
      map.name = name
    }
  
    // 记录地图文件
    const fileName = 'map_' + map.id + '.json'
    const filePath = config.mapsPath + fileName
    map.file = fileName
    
    let data = await fs.promises.readFile(filePath)
    data = JSON.parse(data)
    
    data.name = name
    
    // 保存文件
    const buffer = JSON.stringify(data)
    await fs.promises.writeFile(filePath, buffer)
  }
  
  // 删除某一节点
  async deleteMap (id) {
    let data = this.getParentById(id)
    let spliceArr = []
    if (data) {
      spliceArr = data.obj.splice(data.index, 1)
    }
    
    if (spliceArr.length > 0 && spliceArr[0] && spliceArr[0].file) {
      // 如果有地图文件，一起删除
      const fileName = 'map_' + id + '.json'
      const filePath = config.mapsPath + fileName
      await fs.promises.unlink(filePath)      
    }
  }
  
  // 递归，根据id查找目标的父节点
  getParentById (id) {
    if (!id) {
      return null
    }
    
    // 根节点中找到
    const index = this.maps.findIndex(item => item.id === id)
    if (index >= 0) {
      return {
        index: index,
        obj: this.maps
      }
    }
    
    const len = this.maps.length
    // 递归遍历子节点
    for (let i = 0; i < len; i++) {
      let result = this.findParentById(this.maps[i], id)
      if (result) {
        return result
      }
    }
    
    return null
  }
  
  findParentById (obj, id) {
    if (obj.children) {
      const index = obj.children.findIndex(item => item.id === id)
      if (index >= 0) {
        return {
          index: index,
          obj: obj.children
        }
      }
           
      const len = obj.children.length
      for (let i = 0; i < len; i++) {
        let result = this.findParentById(obj.children[i], id)
        if (result) {
          return result
        }
      }
    }
    
    return null
  }
  
  // 递归从mapData中找到对应的地图对象
  getMapById (id) {
    if (!id) {
      return null
    }
    
    const len = this.maps.length
    
    for (let i = 0; i < len; i++) {
      let result = this.findMapById(this.maps[i], id)
      if (result) {
        return result
      }
    }
    
    return null
  }
  
  // 递归函数找map
  findMapById (obj, id) {
    if (obj.id === id) {
      return obj
    }
    
    if (obj.children) {
      const len = obj.children.length
      for (let i = 0; i < len; i++) {
        let result = this.findMapById(obj.children[i], id)
        if (result) {
          return result
        }
      }
    }
    
    return null
  }
}

module.exports = MapsSetting